#!/usr/bin/env python

##  flamingo - 2D Game Engine
##  Copyright (C) 2009 Bradley Zeis
##
##  This program is free software: you can redistribute it and/or modify
##  it under the terms of the GNU General Public License as published by
##  the Free Software Foundation, either version 3 of the License, or
##  (at your option) any later version.
##
##  This program is distributed in the hope that it will be useful,
##  but WITHOUT ANY WARRANTY; without even the implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##  GNU General Public License for more details.
##
##  You should have received a copy of the GNU General Public License
##  along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##  Bradley Zeis
##  flamingoengine@gmail.com

"""The core Game related classes and functions."""

import sys
import os
import thread
import math

import constants
import fltime
import core
import display
import util
import flmath
import event
import image
import sprite
import objects
import audio
import screen

import OpenGL.GL as gl

class Game(object):
    """Base class used to create Games."""
    def __init__(self):
        core.GAME = self
        self.data = core._Data

        self.data.screen_size = (800, 600)
        self.data.master_spr_group = sprite._MasterGroup()
        self.data.painter = screen.Painter()
        
        self.data.master_clock = fltime.Clock()
        self.data.render_clock = fltime.Clock()
        self.data.logic_clock = fltime.Clock()
        fltime._set_master_clock(self.data.master_clock)
        
        self.data.master_eventlistener = event.EventListener()
        self.data.eventlistener = self.data.master_eventlistener

        ## Open ini file(s) here to load settings.
        audio.load("flamingo.backends.audio.pygame_mixer")

    def run(self, start_game, flags, *args):
        """Runs the entire application.

        Returns: None
        """
        self._run_init()
        self.init(*args)
        self.start_main(start_game)

    ##-------- Initialization
    def _run_init(self):
        """Initialize the application before running.

        Returns: None
        """
        display.load('flamingo.backends.display.pygame_display',
                     'flamingo.backends.event.pygame_event')
        display.init(800, 600, self.data.screen_title)

        ## OpenGL
        gl.glShadeModel(gl.GL_SMOOTH)
        gl.glClearColor(0, 0, 0, 1)
        gl.glDisable(gl.GL_DEPTH_TEST)
        gl.glDisable(gl.GL_LIGHTING)
        
        gl.glEnable(gl.GL_BLEND)
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        
        gl.glEnable(gl.GL_POINT_SMOOTH)
        gl.glEnable(gl.GL_LINE_SMOOTH)
        gl.glEnable(gl.GL_POLYGON_SMOOTH)

        # Flamingo
        self.data.eventlistener.bind(self.quit_all, constants.QUIT, constants.QUIT)

        audio.mixer.init()
        self.quit = False

    def init(self, *args):
        """User initialization.

        Returns: None
        """
        pass

    ##-------- Screens
    def add_screen(self, screen):
        """Add a Screen to the stack.

        screen      - (Screen)

        Returns: None
        """
        self.data.screens.append(screen)

    def rem_screen(self, screen):
        """Remove a Screen from the stack.

        screen      - (Screen)

        Returns: None
        """
        self.data.screens.remove(screen)

    ##--------- Startup
    def start_main(self, start_game=False):
        """Runs the entire program.

        Returns: None
        """
        ## Initialize

        ## Main Loop
        #audio.mixer.start()
        if start_game:
            self.start_game()

        self._gameloop()

        ## Tear Down

    def start_game(self):
        """Starts the threads relating to the game itself.

        Returns: None
        """
        pass

    ##-------- Loop/Quitting
    def _gameloop(self):
        """The main game loop.

        Returns: None
        """
        self.data.master_clock.init()
        self.data.logic_clock.init()
        self.data.render_clock.init()
        
        self.quit = False

        self.data.current_time = self.data.master_clock.ticks()
        timestep = 1.0 / self.data.logic_fps
        accumulator = 0

        while not self.quit:
            
            self.data.master_clock.sync()
            newTime = self.data.master_clock.ticks()
            self.data.delta_time = newTime - self.data.current_time
            self.data.current_time = newTime
            fltime._timer_sync(self.data.current_time)

            accumulator += self.data.delta_time

            ## Process Input
            event.process()

            if self.quit:
                break

            ## Update Physics/Objects
            while accumulator>=timestep:
                accumulator -= timestep
                # Physics step

            for group in self.data.spr_groups:
                group.update(self.data.delta_time)
            self.data.master_spr_group.update()

            ## Render
            #if not audio.mixer.THREADED:
            #    audio.mixer.Mixer.tick(self.data.delta_time)

            #self.data.screens[0].orientation += .01
            
            self.data.render_clock.sync()
            interpolation = accumulator / timestep
            self.data.painter.draw(interpolation)
            display.flip()
            
            #print fltime.ticks_to_seconds(self.data.current_time)

    def quit_game(self):
        """Exits the main loop of the program without killing everything.

        Returns: None
        """
        self.quit = True
        self.data.clear()

    def quit_all(self):
        """Kills the entire application cleanly.

        Returns: None
        """
        self.quit = True
        sys.exit()
